#ifndef W25Q_H
#define W25Q_H

#include "main.h"
#include "spi.h"
#include "string.h"
#include "stdint.h"
#include "stdlib.h"

// user define
#define W25Q128
#define HSPI hspi3
#define FREERTOS
#define MAX_LOG_NUM 10
#ifndef FLASH_CS_Pin
#define FLASH_CS_Pin FLASH_CS_Pin
#endif
#ifndef FLASH_CS_GPIO
#define FLASH_CS_GPIO FLASH_CS_GPIO_Port
#endif
#define Struct_Variable
#define LOG_OPERATE_BUF_SIZE 1200
#define MAX_WRITE_PACK_NUMS 1000
#define LOG_OPERATE_BUF_NORMAL 512
// user define

// system define

#define READ_DELAY 1
#define MAX_READ_BUF 256
#define MAX_WRITE_BUF 256
#define GET_RAM_ADDR(a) (uint32_t)&(a)

typedef enum{
    SEARCH_FLASH,
    FLASH_IDLE,
    FLASH_WAIT,
    FLASH_BUSY
}Flash_State;

typedef struct
{
    uint8_t flash_exsit_if;
    uint16_t wait_ms;
    uint16_t now_ms_cnt;
    Flash_State flash_state;
    Flash_State next_flash_state;

    uint8_t read_buf[MAX_READ_BUF];
    uint8_t start_read;
    uint32_t read_addr;
    uint16_t read_len;

    uint8_t write_buf[MAX_WRITE_BUF];
    uint8_t start_write;
    uint32_t write_addr;
    uint16_t write_len;

    uint16_t to_read_sector_id;
    uint8_t read_sector;

    uint16_t to_clear_sector_id;
    uint8_t clear_sector;

    uint8_t clear_all;

    uint32_t now_ptr_addr;
    uint32_t flash_use_size;
}flash_controller_t;

extern flash_controller_t flash_controller;


#define CS_H HAL_GPIO_WritePin(FLASH_CS_GPIO, FLASH_CS_Pin, GPIO_PIN_SET)
#define CS_L HAL_GPIO_WritePin(FLASH_CS_GPIO, FLASH_CS_Pin, GPIO_PIN_RESET)

#ifdef FREERTOS
    #include "cmsis_os.h"
    #define DELAY(t) osDelay(t) 
#elif NO_FREERTOS
    #define DELAY(t) HAL_Delay(t)
#endif // DEBUG

#ifdef W25Q16
#define FLASH_ID 0x00004015
#define FLASH_MAX_SIZE (2*1024)
#endif

#ifdef W25Q128
#define FLASH_ID 0x00004018
#define FLASH_MAX_SIZE (16*1024)
#endif

#define PAGE_SIZE 256
#define SECTOR_SIZE 4096
#define SECTOR_NUM FLASH_MAX_SIZE * 1024 / SECTOR_SIZE
#define BLOCK_NUM SECTOR_NUM / 64

#define READ_ID 0x9F
#define ALLOW_WRITE 0x06
#define CLEAR_ALL 0xC7
#define CHECK_BUSY 0x05
#define READ_DATA 0x03
#define CLEAR_SECTOR 0x20 
#define WRITE_PAGE 0x02

#define LOG_USAGE_ADDRESS_OFFSET 0x00000000
#define LOG_USAGE_LENGTH 0x03
#define LOG_NUM_ADRESS_OFFSET 0x00000003
#define LOG_NUM_LENGTH 0x02
#define INIT_LOG_ADRESS_OFFSET 0x0000000F

#define LOG_TYPE_ADDRESS_OFFSET                 0x00000005
#define LOG_ID_ADDRESS_OFFSET                   0x00000006
#define LOG_MAX_NUM_ADRESS_OFFSET               0x00000008

#define LOG_NORMAL_VAR_NUM_ADDRESS_OFFSET       0x0000000A
#define LOG_NORMAL_VAR_TYPE_ADDRESS_OFFSET      0x0000000B

void flash_controller_init(void);
void flash_controller_auto(void);


void clear_flash(void);
void read_flash(uint32_t addr_start, uint16_t read_len);
uint8_t check_busy(void);
void wait_busy(void);
void clear_sector(uint16_t sector_id);
void write_flash(uint32_t addr_start, uint16_t write_len);

extern uint8_t flash_operate_buf[SECTOR_SIZE];
void clear_operate_buf(void);

uint8_t rewrite_flash(uint8_t* write_buf,uint32_t addr_start, uint32_t write_len);
void clean_data(uint32_t addr_start, uint32_t data_len);
void get_flash_data(uint8_t* read_buf, uint32_t addr,uint16_t read_len);
void fill_data(uint8_t data, uint32_t addr_start, uint32_t data_len);
void read_sector(uint8_t* read_buf, uint16_t sector_id);
// system define




//#ifdef Struct_Variable

//#include "variable_support.h"

//#define MAX_Variable_NUM 50
//#define MAX_INIT_LOG_NUM 100


//typedef struct
//{
//    Variable_TYPE type;
//    Variable_data data;
//    uint32_t data_ram_addr;
//}Variable_pack_t;

//typedef struct{
//    Variable_TYPE type;
//    uint32_t data_ram_addr;
//}Save_Variable_pack_t;

//typedef struct
//{
//    uint8_t now_num;
//    Save_Variable_pack_t variable_packs[MAX_Variable_NUM];
//    uint16_t data_len;
//}Save_variable_packs_list_t;

//extern Save_variable_packs_list_t save_Variable_list;
//void REGISTER_SAVE_VARIABLES(uint32_t var_ram_addr, Variable_TYPE type);

//void clear_save_list(void);


//typedef struct
//{
//    uint8_t now_num;
//    Variable_pack_t variable_packs[MAX_Variable_NUM];
//    uint16_t data_len;
//}variable_packs_list_t;

//void add_variable_pack(Variable_pack_t var_pack);
//void update_variable_pack_list(void);

//extern variable_packs_list_t variable_packs_list;


//static inline void REGISTER_VARIABLE(uint32_t variable_ram_addr, Variable_TYPE types){
//    Variable_pack_t var_pack = {.data_ram_addr = variable_ram_addr, .type = types};
//    add_variable_pack(var_pack);
//} 

//static inline void DEL_VARIABLE(uint32_t variable_ram_addr){
//    for(int i=0;i<variable_packs_list.now_num;i++){
//        if(variable_packs_list.variable_packs[i].data_ram_addr == variable_ram_addr){
//            for(int j=i;j<variable_packs_list.now_num - 1;j++){
//                memcpy(&variable_packs_list.variable_packs[j], &variable_packs_list.variable_packs[j + 1], sizeof(variable_packs_list.variable_packs[j + 1]));
//            }
//            variable_packs_list.now_num --;
//            break;
//        }
//    }
//}

//#elif Struct_File

//#endif


#endif

/***
 *flash struct
    usage_H usage_M usage_L Log_nums_H Log_nums_L           5 bytes

    Type FLIGHT_LOG
    space 0x00 * 5                                          5 bytes
	LOG_TYPE                                                1 bytes
    Log_Id_H Log_Id_L                                       2 bytes
    MAX_PACK_NUMS_H MAX_PACK_NUMS_L                         2 bytes

    Var_data_Num                                            1 bytes
    register var type list ...                              n bytes
    variables ...                                           n bytes(n <= MAX_PACK_NUMS * EACH_LENGTH)
     
    Type NORMAL_LOG
    space 0x00 * 5                                          5 bytes
    LOG_TYPE                                                1 bytes
    Log_Id_H Log_Id_L                                       2 bytes
    MAX_PACK_NUMS_H MAX_PACK_NUMS_L                         2 bytes

    NOW_OFFSET_H NOW_OFFSET_L                               2 bytes                                              
    Value                                                   n bytes

    Next_Start_ADDR_H Next_Start_ADDR_M Next_Start_ADDR_L   3 bytes

    Type SETTING_LOG
    space 0x00 * 5                                          5 bytes
	LOG_TYPE                                                1 bytes
    Log_Id_H Log_Id_L                                       2 bytes
    MAX_PACK_NUMS_H MAX_PACK_NUMS_L                         2 bytes

    loop
        var_type                                            1 bytes
        variable_bytes                                      n bytes(n <= 8)        
***/

